Skip to content

Method: renderPost(Content, Optional)

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * NorthernWind - lightweight CMS
5: * http://tidalwave.it/projects/northernwind
6: *
7: * Copyright (C) 2011 - 2025 Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/northernwind-src
22: * git clone https://github.com/tidalwave-it/northernwind-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.northernwind.frontend.ui.component.rssfeed;
27:
28: import javax.annotation.Nonnull;
29: import java.util.ArrayList;
30: import java.util.Collection;
31: import java.util.Date;
32: import java.util.List;
33: import java.util.Optional;
34: import com.sun.syndication.feed.rss.Channel;
35: import com.sun.syndication.feed.rss.Content;
36: import com.sun.syndication.feed.rss.Guid;
37: import com.sun.syndication.feed.rss.Item;
38: import com.sun.syndication.io.WireFeedOutput;
39: import it.tidalwave.util.Finder;
40: import it.tidalwave.util.Key;
41: import it.tidalwave.util.NotFoundException;
42: import it.tidalwave.northernwind.core.model.HttpStatusException;
43: import it.tidalwave.northernwind.core.model.RequestLocaleManager;
44: import it.tidalwave.northernwind.core.model.ResourceProperties;
45: import it.tidalwave.northernwind.core.model.SiteNode;
46: import it.tidalwave.northernwind.core.model.SiteProvider;
47: import it.tidalwave.northernwind.frontend.ui.RenderContext;
48: import it.tidalwave.northernwind.frontend.ui.component.blog.DefaultBlogViewController;
49: import it.tidalwave.northernwind.core.impl.model.DefaultSiteFinder;
50: import lombok.extern.slf4j.Slf4j;
51: import static java.util.Collections.emptyMap;
52: import static it.tidalwave.northernwind.core.model.Content.*;
53:
54: /***************************************************************************************************************************************************************
55: *
56: * @author Fabrizio Giudici
57: *
58: **************************************************************************************************************************************************************/
59: @Slf4j
60: public class DefaultRssFeedViewController extends DefaultBlogViewController implements RssFeedViewController
61: {
62: @Nonnull
63: private final SiteProvider siteProvider;
64:
65: @Nonnull
66: private final SiteNode siteNode;
67:
68: @Nonnull
69: private final RssFeedView view;
70:
71: private final List<Item> items = new ArrayList<>();
72:
73: private final String linkBase;
74:
75: private final Channel feed;
76:
77: private final ResourceProperties properties;
78:
79: /***********************************************************************************************************************************************************
80: *
81: **********************************************************************************************************************************************************/
82: public DefaultRssFeedViewController (@Nonnull final RssFeedView view,
83: @Nonnull final SiteNode siteNode,
84: @Nonnull final SiteProvider siteProvider,
85: @Nonnull final RequestLocaleManager requestLocaleManager)
86: {
87: super(siteNode, view, requestLocaleManager);
88: this.siteProvider = siteProvider;
89: this.siteNode = siteNode;
90: this.view = view;
91: feed = new Channel("rss_2.0");
92: properties = siteNode.getPropertyGroup(view.getId());
93: linkBase = properties.getProperty(P_LINK).orElse("");
94: feed.setTitle(properties.getProperty(P_TITLE).orElse(""));
95: feed.setDescription(properties.getProperty(P_DESCRIPTION).orElse(""));
96: feed.setLink(linkBase); // FIXME: why not site.createLink()?
97: feed.setCopyright(properties.getProperty(P_CREATOR).orElse(""));
98: }
99:
100: /***********************************************************************************************************************************************************
101: * {@inheritDoc}
102: **********************************************************************************************************************************************************/
103: @Override
104: public void prepareRendering (@Nonnull final RenderContext context)
105: throws HttpStatusException
106: {
107: // do not call super!
108: log.info("prepareRendering(RenderContext) for {}", siteNode);
109: prepareBlogPosts(context, getViewProperties());
110: }
111:
112: /***********************************************************************************************************************************************************
113: * {@inheritDoc}
114: *
115: * RSS must not present their inner contents to the sitemap.
116: **********************************************************************************************************************************************************/
117: @Override @Nonnull
118: public Finder<SiteNode> findVirtualSiteNodes()
119: {
120: return new DefaultSiteFinder<>("empty", emptyMap(), null); // TODO: HierarchicFinderSupport.emptyFinder();
121: }
122:
123: /***********************************************************************************************************************************************************
124: * {@inheritDoc}
125: **********************************************************************************************************************************************************/
126: @Override
127: protected void renderPosts (@Nonnull final List<? extends it.tidalwave.northernwind.core.model.Content> fullPosts,
128: @Nonnull final List<? extends it.tidalwave.northernwind.core.model.Content> leadinPosts,
129: @Nonnull final List<? extends it.tidalwave.northernwind.core.model.Content> linkedPosts)
130: throws Exception
131: {
132: fullPosts.forEach (post -> renderPost(post, Optional.of(P_FULL_TEXT)));
133: leadinPosts.forEach(post -> renderPost(post, Optional.of(P_LEADIN_TEXT)));
134: linkedPosts.forEach(post -> renderPost(post, Optional.empty()));
135:
136: feed.setGenerator("NorthernWind v" + siteProvider.getVersionString());
137: feed.setItems(items);
138:
139: // if (!StringUtils.hasText(feed.getEncoding()))
140: // {
141: // feed.setEncoding("UTF-8");
142: // }
143:
144: final var feedOutput = new WireFeedOutput();
145: view.setContent(feedOutput.outputString(feed));
146: }
147:
148: /***********************************************************************************************************************************************************
149: * {@inheritDoc}
150: **********************************************************************************************************************************************************/
151: protected void renderPost (@Nonnull final it.tidalwave.northernwind.core.model.Content post,
152: @Nonnull final Optional<? extends Key<String>> textProperty)
153: {
154: final var blogDateTime = post.getProperty(DATE_KEYS).orElse(TIME0);
155: // FIXME: compute the latest date, which is not necessarily the first
156:• if (feed.getLastBuildDate() == null)
157: {
158: feed.setLastBuildDate(Date.from(blogDateTime.toInstant()));
159: }
160:
161: final var postProperties = post.getProperties();
162: final var item = new Item();
163: final var content = new Content();
164: // FIXME: text/xhtml?
165: content.setType("text/html"); // FIXME: should use post.getResourceFile().getMimeType()?
166: textProperty.flatMap(postProperties::getProperty).ifPresent(content::setValue);
167: item.setTitle(postProperties.getProperty(P_TITLE).orElse(""));
168: // item.setAuthor("author " + i); TODO
169: item.setPubDate(Date.from(blogDateTime.toInstant()));
170: item.setContent(content);
171:
172: try
173: {
174: // FIXME: manipulate through site.createLink()
175: final var link = linkBase.replaceAll("/$", "") + post.getExposedUri().orElseThrow(NotFoundException::new).asString() + "/";
176: final var guid = new Guid();
177: guid.setPermaLink(true);
178: guid.setValue(link);
179: item.setGuid(guid);
180: item.setLink(link);
181: }
182: catch (NotFoundException e)
183: {
184: // ok. no link
185: }
186:
187: items.add(item);
188: }
189:
190: /***********************************************************************************************************************************************************
191: * {@inheritDoc}
192: **********************************************************************************************************************************************************/
193: @Override
194: protected void renderTagCloud (@Nonnull final Collection<? extends TagAndCount> tagsAndCount)
195: {
196: // not meaningful for RSS
197: }
198: }